package com.autumn.oauth2.zero.userdetails;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import com.autumn.mybatis.criterion.Query;
import com.autumn.oauth2.zero.domain.entities.AbstractUser;
import com.autumn.oauth2.zero.domain.entities.AbstractUserLoginProvider;
import com.autumn.oauth2.zero.domain.repositories.IUserBaseRepository;
import com.autumn.oauth2.zero.domain.repositories.IUserLoginProviderBaseRepository;
import com.autumn.runtime.session.claims.IdentityClaims;
import com.autumn.security.core.userdetails.AccountNotFoundException;
import com.autumn.security.core.userdetails.IAutumnUserDetails;
import com.autumn.security.core.userdetails.ProviderNotFoundException;
import com.autumn.security.core.userdetails.UserProviderLoginInfo;
import com.autumn.util.reflect.ReflectUtils;
import com.autumn.validation.MatchesUtils;
import com.autumn.validation.ValidationUtils;

/**
 * 用户抽象服务
 * 
 * @author 老码农 2018-04-10 00:16:23
 * @param <TUser>
 *            用户类型
 * @param <TUserLoginProvider>
 *            用户登录提供者类型
 */
public abstract class AbstractAutumnUserService<TUser extends AbstractUser, TUserLoginProvider extends AbstractUserLoginProvider>
		implements IAutumnUserBaseService<TUser, TUserLoginProvider> {

	/**
	 * 用户类型
	 */
	protected final Class<TUser> userClass;

	/**
	 * 用户登录提供者类型
	 */
	protected final Class<TUserLoginProvider> userLoginProviderClass;

	@Autowired
	protected IUserBaseRepository<TUser> userRepository;

	@Autowired
	protected IUserLoginProviderBaseRepository<TUserLoginProvider> userLoginProviderRepository;

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public AbstractAutumnUserService() {
		Map<String, Class<?>> argMap = ReflectUtils.getGenericActualArgumentsTypeMap(this.getClass());
		this.userClass = (Class<TUser>) argMap.get("TUser");
		this.userLoginProviderClass = (Class<TUserLoginProvider>) argMap.get("TUserLoginProvider");
	}

	@Override
	public TUser loadUserByUsername(String username) throws AccountNotFoundException {
		Query query = new Query(this.userClass);
		if (MatchesUtils.isMobilePhone(username)) {
			query.eq("mobilePhone", username);
		} else if (MatchesUtils.isEmail(username)) {
			query.eq("mailAddress", username);
		} else {
			query.eq("username", username);
		}
		query.eq("isDelete", false);
		TUser user = userRepository.selectFirst(query.builderSection());
		if (user == null) {
			throw new AccountNotFoundException("用户名或密码错误。");
		}
		this.loadAuthority(user);
		return user;
	}

	/**
	 * 
	 */
	@Override
	public IAutumnUserDetails loadUserByMobile(String mobilePhone) throws AccountNotFoundException {
		Query query = new Query(this.userClass);
		query.eq("mobilePhone", mobilePhone).eq("isDelete", false);
		TUser user = userRepository.selectFirst(query.builderSection());
		if (user == null) {
			throw new AccountNotFoundException("手机号码未注册。");
		}
		this.loadAuthority(user);
		return user;
	}

	private TUserLoginProvider getUserByProvider(UserProviderLoginInfo userProviderLoginInfo) {
		ValidationUtils.validation(userProviderLoginInfo);
		Query query = new Query(this.userLoginProviderClass);
		query.eq("loginProvider", userProviderLoginInfo.getLoginProvider()).eq("providerKey",
				userProviderLoginInfo.getProviderKey());
		TUserLoginProvider userLoginProvider = userLoginProviderRepository.selectFirst(query.builderSection());
		return userLoginProvider;
	}

	@Override
	public TUser loadUserByProvider(UserProviderLoginInfo userProviderLoginInfo) throws ProviderNotFoundException {
		TUserLoginProvider userLoginProvider = this.getUserByProvider(userProviderLoginInfo);
		if (userLoginProvider == null) {
			throw new ProviderNotFoundException("无效的登录提供者。");
		}
		TUser user = userRepository.get(userLoginProvider.getUserId());
		if (user == null) {
			throw new ProviderNotFoundException("无效的登录提供者。");
		}
		this.loadAuthority(user);
		return user;
	}

	@Override
	public boolean existUserProvider(UserProviderLoginInfo userProviderLoginInfo) {
		TUserLoginProvider userLoginProvider = this.getUserByProvider(userProviderLoginInfo);
		if (userLoginProvider == null) {
			return false;
		}
		Query query = new Query(this.userClass);
		query.eq("id", userLoginProvider.getUserId()).eq("isDelete", false);
		return userRepository.countByWhere(query.builderSection()) > 0;
	}

	/**
	 * 加载权限
	 * 
	 * @param user
	 *            用户
	 */
	private void loadAuthority(TUser user) {
		IdentityClaims identityClaims = this.buildIdentityClaims(user);
		user.setIdentityClaims(identityClaims);
	}

	/**
	 * 生成声明
	 * 
	 * @param user
	 *            用户
	 * @return
	 *
	 */
	protected abstract IdentityClaims buildIdentityClaims(TUser user);
}
